﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Melee.Controller.Handlers;

namespace Melee.Controller.Comet
{
    class CometObserver
    {
        private const Int32 REMOVE_INVALID_LISTENER_COUNT = 60;
        private Timer m_timer = null;
        private IDictionary<Guid, Listener> m_listenerCache = new Dictionary<Guid, Listener>();
        private Int32 m_timerCount = 1;

        public CometObserver()
        {
            m_timer = new Timer(CheckingListener, null, 0, 10000);
        }

        public void Add(Guid loginId, string userName)
        {
            if (!m_listenerCache.ContainsKey(loginId))
            {
                lock (this)
                {
                    if (!m_listenerCache.ContainsKey(loginId))
                        m_listenerCache.Add(loginId, new Listener(loginId, userName));
                }
            }
        }

        public void Comet(Guid loginId, string userName, AsyncResult asyncResult)
        {
            Listener listerner;
            if (m_listenerCache.TryGetValue(loginId, out listerner))
            {
                listerner.AsyncResult = asyncResult;
            }
            else
            {
                Add(loginId, userName);
                Comet(loginId, userName, asyncResult);
            }
        }

        public void SendMessage(Message message, string to = null)
        {
            lock (this)
            {
                Parallel.ForEach(m_listenerCache.Values, listener => listener.Listen(message, to));
            }
        }

        private void CheckingListener(object state)
        {
            lock (this)
            {
                Parallel.ForEach(m_listenerCache.Values, listener =>
                {
                    if (listener.IsConnectedToolong)
                        listener.Disconnected();
                });
                if (++m_timerCount == REMOVE_INVALID_LISTENER_COUNT)
                {
                    IEnumerable<Guid> invalidLoginIds = m_listenerCache.Where(item => item.Value.IsInvalid).Select(item => item.Key);
                    foreach (Guid loginId in invalidLoginIds)
                    {
                        m_listenerCache.Remove(loginId);
                    }
                    m_timerCount = 1;
                }
            }
        }
    }
}
